package com.lc.context;

import com.lc.config.annos.*;
import javafx.util.Pair;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @author liuc
 * @date 2021/4/18
 * @description bean的一些基本属性封装
 **/
@Exclude
public class BeanDefinition {
    //beanId
    private String beanId;
    //类名
    private String className;
    //bean对象
    private Object bean;
    //类
    private Class<?> cls;
    //父类
    private List<Class<?>> clzs = new ArrayList<>();
    //需要代理
    private boolean needProxy;
    //只能cglib代理
    private boolean cglibProxy;
    //需要注入
    private boolean needPropagate;
    //需要注入的field
    private List<Field> needPropagateFields = new ArrayList<>();

    private boolean isBean;

    public BeanDefinition(String className) {
        Class c = null;
        try {
            c = Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        if(c!= null && !c.isInterface()){
            this.className = className;
            this.cls = c;
            component();
            if(isBean){
                clzs();
                needProxy();
                needPropagate();
            }
        }
    }

    private void component(){
        this.isBean = false;
        for (Annotation annotation : this.cls.getAnnotations()) {
            if(annotation instanceof Component){
                Component component = (Component) annotation;
                String beanId = "".equals(component.value()) ? this.className : component.value();
                this.isBean = true;
                this.beanId = beanId;
            }
            if(annotation instanceof Repository){
                Repository component = (Repository) annotation;
                String beanId = "".equals(component.value()) ? this.className : component.value();
                this.isBean = true;
                this.beanId = beanId;
            }
            if(annotation instanceof Service){
                Service component = (Service) annotation;
                String beanId = "".equals(component.value()) ? this.className : component.value();
                this.isBean = true;
                this.beanId = beanId;
            }
        }
    }

    private void clzs(){
        this.clzs.add(cls);
        Class c = this.cls.getSuperclass();
        if(c != Object.class){
            this.clzs.add(c);
        }
        Class[] is = this.cls.getInterfaces();
        if(is != null && is.length != 0){
            for (Class i : is) {
                this.clzs.add(i);
            }
        }
    }

    private void needProxy(){
        for (Class<?> clz : this.clzs) {
            Method[] methods = clz.getMethods();
            for (Method method : methods) {
                Annotation[] annotations = method.getAnnotations();
                if (annotations == null || annotations.length == 0) continue;
                for (Annotation annotation : annotations) {
                    if(annotation instanceof Transactional){
                        this.needProxy = true;
                        return;
                    }
                }
            }
        }
    }

    private void needPropagate(){
        Field[] fields = cls.getDeclaredFields();
        for (Field field : fields) {
            Annotation[] annotations = field.getAnnotations();
            if (annotations == null || annotations.length == 0) return;
            for (Annotation annotation : annotations) {
                if(annotation instanceof Autowired){
                    this.needPropagate = true;
                    this.needPropagateFields.add(field);
                    this.cglibProxy = true;
                }
            }
        }
    }

    private Object createBean()  {
        if(this.bean != null) return this.bean;
        try {
            this.bean = this.cls.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return this.bean;
    }

    public String getBeanId() {
        return beanId;
    }

    public String getClassName() {
        return className;
    }

    public Class<?> getCls() {
        return cls;
    }

    public List<Class<?>> getClzs() {
        return clzs;
    }

    public boolean isNeedProxy() {
        return needProxy;
    }

    public boolean isNeedPropagate() {
        return needPropagate;
    }

    public List<Field> getNeedPropagateFields() {
        return needPropagateFields;
    }

    public boolean isBean() {
        return isBean;
    }

    public Object getBean() {
        return createBean();
    }

    public void setBean(Object bean) {
        this.bean = bean;
    }

    public boolean isCglibProxy() {
        return cglibProxy;
    }

    public void setCglibProxy(boolean cglibProxy) {
        this.cglibProxy = cglibProxy;
    }
}
